#include <stdio.h>
#include <string.h>
#include "relic.h"
#include "sqft_conf.h"
#include <math.h>
#include <sys/time.h>

/**--------------------------------------------------------------------*/
/**
 * Funcao para calculo de intervalo de tempo de execuao
 * Precisao: microsegundos (us)
 */
 
long long unsigned getTimeDifff(struct timeval start, struct timeval stop) {
	long long unsigned time;
	time = (float) (stop.tv_sec - start.tv_sec)*1000000;
	time += ((float)(stop.tv_usec - start.tv_usec));
	return time;
}


/**--------------------------------------------------------------------*/

int main(int argc, char *argv[]) {
	int MAX;
	long long unsigned acc_rabin, acc_sqft;
	struct timeval start, stop;
	FILE *fp_rabin, *fp_sqft;
	int bits, i, j;
	//int sts[4];
	bn_t p;
	
	if (core_init() != STS_OK) {
		core_clean();
		return 1;
	}
	
	fp_rabin = fopen("sts/lier_rabin.dat", "w");
	fp_sqft = fopen("sts/lier_sqft.dat", "w");
	fprintf(fp_rabin, "# Rabin \n");
	fprintf(fp_sqft, "# SQFT \n");
	
	bn_null(p);
	bn_new(p);
	
	if (argc > 1) {
		bits = atoi(argv[1]);
		
		for (i=0; i<20; i++) {
			bn_gen_prime(p, bits);
			
			gettimeofday(&start, NULL);
			bn_is_prime_sqft(p);
			gettimeofday(&stop, NULL);
			fprintf(fp_sqft, "%d %llu\n", i, getTimeDifff(start, stop));
			
			gettimeofday(&start, NULL);
			bn_is_prime_rabin(p);
			gettimeofday(&stop, NULL);
			fprintf(fp_rabin, "%d %llu\n", i, getTimeDifff(start, stop));
		}
		
	}
	else {
		MAX = 20;
		for (bits=32; bits<=BN_BITS; bits *= 2) {
			acc_sqft=0;
			acc_rabin=0;
			printf("Getting times for %d BITS\n", bits);
			
			for (j=0; j<MAX; j++) {
				do {
					bn_rand(p, BN_POS, bits);
				} while (bn_is_prime(p));
					
				gettimeofday(&start, NULL);
				if (bn_is_prime_basic(p)) {
					if (bn_is_prime_rabin(p)) {
						printf("\nWTF - ERROR RABIN\n");
						return 1;
					}
				}
				gettimeofday(&stop, NULL);
			
				acc_rabin += getTimeDifff(start, stop);

				
				gettimeofday(&start, NULL);
				if (bn_is_prime_basic(p)) {
					if (bn_is_prime_sqft(p)) {
						printf("\nWTF - ERROR SQFT\n");
						bn_print(p);
						return 1;
					}
				}
				gettimeofday(&stop, NULL);
			
				acc_sqft += getTimeDifff(start, stop);

			}
		fprintf(fp_sqft, "%d %llu\n", (int) log2((double) bits), acc_sqft);
		fprintf(fp_rabin, "%d %llu\n", (int) log2((double) bits), acc_rabin);
		}
	}

	
	
	bn_free(p);
	fclose(fp_rabin);
	fclose(fp_sqft);
	core_clean();
	return 0;
}
